<?php
namespace PsiFramework\Classes\Util;

use PsiFramework\Classes\Util\UI\Printer;

import("Classes.Factory.ActionFactory");
import("Classes.Factory.ObjectFactory");
import("Classes.Factory.ServiceFactory");
import("Classes.Util.HTTP.Request");
import("Classes.Util.HTTP.Session");
import("Classes.Util.Log.Logger");
import("Classes.Util.Manager.ApplicationManager");
import("Classes.Util.Manager.ObjectManager");
import("Classes.Util.UI.LanguageManager");
import("Classes.Util.UI.TemplateManager");

use \PsiFramework\Classes\Exceptions\SecurityException;
use \PsiFramework\Classes\Factory\ActionFactory;
use \PsiFramework\Classes\Factory\ObjectFactory;
use \PsiFramework\Classes\Factory\ServiceFactory;
use \PsiFramework\Classes\Util\HTTP\AuthenticationManager;
use \PsiFramework\Classes\Util\HTTP\Request;
use \PsiFramework\Classes\Util\HTTP\Session;
use \PsiFramework\Classes\Util\Log\Logger;
use \PsiFramework\Classes\Util\Manager\ApplicationManager;
use \PsiFramework\Classes\Util\Manager\ObjectManager;
use \PsiFramework\Classes\Util\UI\LanguageManager;
use \PsiFramework\Classes\Util\UI\TemplateManager;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * The Controller class represents the front controller
 *
 * @package Util
 */
class Controller
{

    protected static /*Controller*/ $_singleton ;

    protected /*Session*/            $_session ;
    protected /*Request*/            $_request ;
    protected /*ApplicationManager*/ $_applicationManager ;
    protected /*LanguageManager*/    $_languageManager ;
    protected /*TemplateManager*/    $_templateManager ;

    protected /*Logger*/               $_logger;

    /**
     * Constructeurs
     */
    protected function __construct()
    {
        $this->_session = null;
        $this->_request = null;
        $this->_applicationManager = null;
        $this->_languageManager = null;
        $this->_templateManager = null;

        $this->_logger = new Logger("Controller");
    }

    /**
     * Will execute the action corresponding to the specified
     * variables in session and request
     */
    public final function run()
    {

        $startTime =  microtime(true);
        $this->_logger->debug("Executing front controller");

        //TODO gestion du cache

        $this->_session = Session::getInstance();
        $this->_request = Request::getInstance();
        
        $this->_applicationManager = ApplicationManager::getInstance();
        $this->_languageManager = LanguageManager::getInstance();
        $this->_templateManager = TemplateManager::getInstance();

        $actionFactory = ActionFactory::getInstance();

        //language
        $lang = $this->_request->getParameter("lang");
        if ($lang != null) {
            $this->_languageManager->setLanguage($lang);
        }

        $showTemplate = null ;
        $actionName = $this->_request->getParameter("action");
        $serviceName = $this->_request->getParameter("service");

        try{

            //Routing
            if ($serviceName === null) {

                ApplicationManager::getInstance()->getApplicationWithSecurityCheck();

                $action = $actionFactory->getAction($actionName);

                if ($action != null) {
                    $action->execute(); //we execute the action
                    $showTemplate = $action->getTemplate();
                } else {
                    $action = $actionFactory->getAction('PageNotFound', false);
                    $action->execute();
                    $showTemplate = $action->getTemplate();
                }

            } else {
                $service = ServiceFactory::getInstance()->getService($serviceName);
                $service->execute($this->_request);
            }

        }
        catch(SecurityException $e) {
            if (is_null(
                AuthenticationManager::getInstance()->getAuthenticatedUser()
            )
            ) {
                $action = $actionFactory->getAction('Login', false);
            } else {
                $action = $actionFactory->getAction('Forbidden', false);
                $action->addParameter("error", $e);
            }
            $action->execute();
            $showTemplate = $action->getTemplate();
        }
        catch(\Exception $e) {
            $action = $actionFactory->getAction('Error', false);
            $action->addParameter("error", $e);
            $action->execute();
            $showTemplate = $action->getTemplate();
        }

        //Debug Management
        $debug = false ;
        $requestDebug = $this->_request->getParameter("debug");
        if ($requestDebug !== null) {
            if ($requestDebug === "true") {
                $debug = true ;
            }
            $this->_session->set("debug", $debug);
        } else {
            $sessionDebug = $this->_session->get("debug");
            if ($sessionDebug !== null) {
                $debug = $sessionDebug ;
            } else {
                $this->_session->set("debug", false);
            }
        }

        if ($debug) {
            TemplateManager::getInstance()->addFileScript(
                'Applications/DefaultApp/Template/scripts/debug.js'
            );
            TemplateManager::getInstance()->addFileStyle(
                'Applications/DefaultApp/Template/styles/debug.css'
            );
        }

        $endTime = microtime(true);
        $duration = $endTime - $startTime ;
        $this->_logger->debug(
            "Front controller execution time : " . $duration. "s."
        );

        $this->_templateManager->show($showTemplate, $debug);

    }

    /**
     * Function to be called instead of the constructor.
     *
     * @return Controller instance
     */
    public static function getInstance()
    {

        if (self::$_singleton==null) {
            self::$_singleton = new Controller();
        }

        return self::$_singleton;
    }
}
